<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------

// 应用公共文件
/**
 * 所有用到密码的不可逆加密方式
 * @param string $password
 * @param string $password_salt
 * @return string
 */
function encrypt_password($password, $password_salt)
{
    return md5(md5($password) . md5($password_salt));
}
/**
 * 随机字符
 * @param int $length 长度
 * @param string $type 类型
 * @param int $convert 转换大小写 1大写 0小写
 * @return string
 */
function random($length=10, $type='letter', $convert=0)
{
    $config = array(
        'number'=>'1234567890',
        'letter'=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
        'string'=>'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789',
        'all'=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
    );

    if(!isset($config[$type])) $type = 'letter';
    $string = $config[$type];

    $code = '';
    $strlen = strlen($string) -1;
    for($i = 0; $i < $length; $i++){
        $code .= $string{mt_rand(0, $strlen)};
    }
    if(!empty($convert)){
        $code = ($convert > 0)? strtoupper($code) : strtolower($code);
    }
    return $code;
}
/**
 * 数据签名
 * @param array $data 被认证的数据
 * @return string 签名
 */
function data_signature($data = [])
{
    if(!is_array($data)){
        $data = (array)$data;
    }
    ksort($data);
    $code = http_build_query($data);
    $sign = sha1($code);
    return $sign;
}

/**
 * 是否微信
 * @return bool
 */
function is_weixin(){
    if ( strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false ) {
        return true;
    }
    return false;
}

/**
 * 根据用户id获取用户组,返回值为数组
 * @param   int $uid    用户id
 * @return string
 */
function get_groups($uid)
{
    $auth = new \gdbase\Auth();
    $data = $auth->getGroups($uid);

    if(empty($data)){
        return '错误';
    }
    return $data[0]['title'];
}

/**
 * 获取验证错误
 * @param $error
 */
function getValidateErrorText($error){
    $errors = [
        'require' => '不能为空'
    ];

    if(array_key_exists($error,$errors)){
        return $errors[$error];
    }
    else{
        return '未知验证错误';
    }
}

/**
 * 获取指定表名的下拉
 * @param $tableName
 */
function getSelectDropDown($tableName,$id = 'id',$text = 'name',$filter = '',$addField = []){
    $orm = model($tableName);
    $where = [];
    if($orm->softDel){
        $where[] = [$orm->softDel,'<',1];
    }

    if(!empty($orm->projectIdName)){
        $projectId = getProjectId();
        if (!empty($projectId)) {
            $where[] = ['project_id','=',$projectId];
        }
    }


    $field[] = $id . ' AS id';
    $field[] = $text . ' AS text';
    if(!empty($filter)){
        $field[] = $filter;
    }
    $field = array_merge($field,$addField);
    // 增加缓存时间，防止列表时重复读表，缓存 10 分钟
    $dataList = db($tableName)->where($where)->field(join(',',$field) )
        ->cache(true,600,'system')->select();
    return $dataList;
}

function getSelectData($row){
    $selectData = [];
    if(!empty($row['type_value_custom'])){
        if(!empty($row['type_value_custom']['f'])){
            $selectData = getSelectDropDown(
                $row['type_value_custom']['table'],
                $row['type_value_custom']['id'],
                $row['type_value_custom']['text'],
                $row['type_value_custom']['f']
            );
        }
        else{
            $selectData = getSelectDropDown(
                $row['type_value_custom']['table'],
                $row['type_value_custom']['id'],
                $row['type_value_custom']['text']
            );
        }
    }
    else{
        if(!empty($row['type_value'])){
            $selectData = $row['type_value'];
        }
        if(!empty($row['cv'])){
            $tmp = explode('|',$row['cv']);
            $args = [];
            for ($i = 1 ; $i < count($tmp) ; $i ++ ){
                $frist = substr( $tmp[$i], 0, 1 );
                switch ($frist){
                    case '$':// 动态参数，需配合 $item 使用
                        $args[] = [];
                        break;
                    default:
                        // 默认为文本
                        $args[] = $tmp[$i];
                        break;
                }
            }
            $selectData = call_user_func_array($tmp[0],$args);
        }
    }

    return $selectData;
}

/**
 * 获取下拉框HTML
 * @param $fieldRow array 列数据
 * @param string $selectId 选中ID
 */
function getSelectHtml($fieldRow,$selectId = '',$source = false){
    $html = [];
    if(empty($fieldRow['is_tree'])){
        if(is_array($source)){
            $dataList = $source;
        }
        else{
            $dataList = getSelectData($fieldRow);
        }
        foreach ($dataList as $item){
            if($item['id'] == $selectId){
                $html[] = '<option value="'.$item['id'].'" selected>'.$item['text'].'</option>';
            }
            else{
                $html[] = '<option value="'.$item['id'].'">'.$item['text'].'</option>';
            }
        }
    }
    else{
        if(is_array($source)){
            $dataList = $source;
        }
        else{
            $dataList = getSelectTreeData($fieldRow);
        }

        $dataList = getSortedCategory($dataList);
        $html = [];
        foreach ($dataList as $item) {
            if($item['id'] == $selectId){
                $html[] = '<option value="'.$item['id'].'" selected>'.$item['html'].' '.$item['text'].'</option>';
            }
            else{
                $html[] = '<option value="'.$item['id'].'">'.$item['html'].' '.$item['text'].'</option>';
            }

        }
    }

    return join('',$html);
}

function getSelectTreeData($row){
    $selectData = [];
    if(!empty($row['type_value_custom'])){
        if(!empty($row['is_tree']) && !empty($row['tree_parent_id_name'])){
            $selectData = getSelectDropDown(
                $row['type_value_custom']['table'],
                $row['type_value_custom']['id'],
                $row['type_value_custom']['text'],
                $row['type_value_custom']['f'],
                [$row['tree_parent_id_name']]
            );
        }
        else{
            $selectData = getSelectDropDown(
                $row['type_value_custom']['table'],
                $row['type_value_custom']['id'],
                $row['type_value_custom']['text']
            );
        }
    }
    else{
        if(!empty($row['type_value'])){
            $selectData = $row['type_value'];
        }
        if(!empty($row['cv'])){
            $tmp = explode('|',$row['cv']);
            $args = [];
            for ($i = 1 ; $i < count($tmp) ; $i ++ ){
                $frist = substr( $tmp[$i], 0, 1 );
                switch ($frist){
                    case '$':// 动态参数，需配合 $item 使用
                        $args[] = [];
                        break;
                    default:
                        // 默认为文本
                        $args[] = $tmp[$i];
                        break;
                }
            }
            $selectData = call_user_func_array($tmp[0],$args);
        }
    }

    return $selectData;
}

/**
 *
 * @param array $field 列数据
 * @param array $item 列表中当前数据
 * @param array $selectList
 * @return string
 * @throws Exception
 */
function getListSelectValue($field,$item,$selectList = []){
    $fanhui = '';
    switch ($field['type']){
        case 'select':
            if(empty($field['cv'])){
                $selectData = getSelectData($field);
                foreach ($selectData as $datum){
                    if($datum['id'] == $item[$field['name']]){
                        $fanhui = $datum['text'];
                        break;
                    }
                }
            }
            else{
                $fanhui = getListSelectValueCustomValue($field,$item);
            }

            break;
        case 'select_source':
            if(empty($selectList)){
                exception('selectList 为空');
            }
            $selectData = $selectList[$field['type_value_custom']['source']];
            foreach ($selectData as $datum){
                if($datum['id'] == $item[$field['name']]){
                    $fanhui = $datum['text'];
                    break;
                }
            }

            break;
        case 'radio':
        case 'select_empty':
            $fanhui = '无';
            if(empty($field['cv'])){
                $selectData = getSelectData($field);
                foreach ($selectData as $datum){
                    if($datum['id'] == $item[$field['name']]){
                        $fanhui = $datum['text'];
                        break;
                    }
                }
            }
            else{
                $fanhui = getListSelectValueCustomValue($field,$item);
            }

            break;
        case 'date_select':
            if (!empty($item[$field['name']])) {
                $fanhui = date('Y-m-d',$item[$field['name']]);
            }
            break;
        case 'datetime_select':
            if (!empty($item[$field['name']])) {
                $fanhui = date('Y-m-d H:i:s',$item[$field['name']]);
            }
            break;
        case 'text_money':
            $fanhui = '￥' . sprintf('%.2f',($item[$field['name']] / 100));
            break;
        default:
        case 'text':
            $fanhui = $item[$field['name']];
            break;
    }

    return $fanhui;
}

function getListSelectValueCustomValue($field,$item){
    $tmp = explode('|',$field['cv']);
    $args = [];
    for ($i = 1 ; $i < count($tmp) ; $i ++ ){
        $frist = substr( $tmp[$i], 0, 1 );
        switch ($frist){
            case '$':// 动态参数，需配合 $item 使用
                $args[] = $item[substr($tmp[$i],1)];
                break;
            default:
                // 默认为文本
                $args[] = $tmp[$i];
                break;
        }
    }

    return call_user_func_array($tmp[0],$args);
}

function getRadioHtml($fieldRow,$selectId = '',$source = false){
    $html = [];
    if(is_array($source)){
        $dataList = $source;
    }
    else{
        $dataList = getSelectData($fieldRow);
    }
    foreach ($dataList as $item){
        if($item['id'] == $selectId){
            $html[] = '<option value="'.$item['id'].'" selected>'.$item['text'].'</option>';
        }
        else{
            $html[] = '<option value="'.$item['id'].'">'.$item['text'].'</option>';
        }
    }

    return join('',$html);
}

/**
 * 修改config的函数
 * @param $arr1 配置前缀
 * @param $arr2 数据变量
 * @return bool 返回状态
 */
function setConfig($pat, $rep)
{
    /**
     * 原理就是 打开config配置文件 然后使用正则查找替换 然后在保存文件.
     * 传递的参数为2个数组 前面的为配置 后面的为数值.  正则的匹配为单引号  如果你的是分号 请自行修改为分号
     * $pat[0] = 参数前缀;  例:   default_return_type
    $rep[0] = 要替换的内容;    例:  json
     */
    if (is_array($pat) and is_array($rep)) {
        for ($i = 0; $i < count($pat); $i++) {
            $pats[$i] = '/\'' . $pat[$i] . '\'(.*?),/';
            $reps[$i] = "'". $pat[$i]. "'". "=>" . "'".$rep[$i] ."',";
        }
        $fileurl = APP_PATH . "config.php";
        $string = file_get_contents($fileurl); //加载配置文件
        $string = preg_replace($pats, $reps, $string); // 正则查找然后替换
        file_put_contents($fileurl, $string); // 写入配置文件
        return true;
    } else {
        return false;
    }
}

/**
 * 加载资源
 * @param $type
 * @param $version
 * @param $files
 * @return string
 */
function load_res($type,$version,$files){
    $htmls = [];
    if(true == config('site.'.$type.'_minify')){
        foreach ($files as $file){
            $htmls[] = $file;
        }
        if('css' == $type){
            return "<link rel=\"stylesheet\" href=\"/assets/?".urlencode(join(',',$htmls))."\">";
        }
        else{
            // js
            return "<script src=\"/assets/?".urlencode(join(',',$htmls))."\"></script>";
        }
    }
    else{
        foreach ($files as $file){
            if('css' == $type){
                $htmls[] = "<link rel=\"stylesheet\" href=\"".$file.'?'.$version."\">";
            }
            else{
                // js
                $htmls[] = "<script src=\"".$file.'?'.$version."\"></script>";
            }
        }

        return join('',$htmls);
    }
}

/**
 * id 进制转换 加密
 * @param int $id
 * @param string $salt 偏移，方便设置每个项目不一样的结果，也可以设置每个数据表不一样
 * @return string
 * @throws Exception
 */
function hashIdEncode($id,$salt = 'gdbase'){
    if(!is_numeric($id)){
        exception('id 只能传入 数字');
    }
    try {
        $hashId = new \Hashids\Hashids($salt);
        // 增加随机数，使每次加密都不一样
//        return $hashId->encode($id,random(2,'number'));
        return $hashId->encode($id,66,88);
    }catch (\Exception $e){
        return '';
    }
}
/**
 * id 进制转换 解密
 * @param string $hashStr
 * @param string $salt 偏移，方便设置每个项目不一样的结果
 * @return string
 * @throws Exception
 */
function hashIdDecode($hashStr,$salt = 'gdbase'){
    try {
        $hashId = new \Hashids\Hashids($salt);
        $tmp = $hashId->decode($hashStr);
        return $tmp[0];
    }catch (\Exception $e){
        exception('解密出错');
        return false;
    }
}

// ----------------------------------------------------- API 帮助 方法 ----------------------------------------------------------------------------------------

/**
 *  API 里面专用 抛出逻辑异常
 *
 * @param string    $msg  异常消息
 * @param integer   $code 异常代码 默认为0
 *
 * @throws Exception
 */
function exceptionLogic($msg, $code = 0)
{
    throw new \app\common\exception\LogicException($msg, $code);
}

/**
 *  API 里面专用 抛出业务异常
 *
 * @param string    $msg  异常消息
 * @param integer   $code 异常代码 默认为0
 *
 * @throws Exception
 */
function exceptionBusiness($msg, $code = 0)
{
    throw new \app\common\exception\BusinessException($msg, $code);
}

/**
 * 按控制器名称，动作名称  解析注解 ， 该方法会缓存 ，更新后请注意清理缓存
 * @param $version
 * @param $controllerName
 * @param $actionName
 * @param bool $annotationName
 * @param string $classNameProfix
 * @return array|bool
 */
function getControllerActionAnnotations($version,$controllerName, $actionName,$annotationName = false,$classNameProfix = 'app\\api'){
    $annotations = new \gdbase\Annotations();
    $className = $classNameProfix . '\\' . $version . '\\' .$controllerName;

    $cacheKey = md5($className) . '_' . $actionName;
    $result = cache($cacheKey);
    // 从缓存读取不到数据，则解析
    if(empty($result)){
        $result = $annotations->getMethodAnnotations( $className ,$actionName);
        // 有返回结果后，进行缓存 调试 模式不进行缓存
//        if(!env('APP_DEBUG')){
//            cache($cacheKey,$result);
//        }
        cache($cacheKey,$result,null,'api');
    }
    //  缓存和解析都没有 填写 注解 直接返回
    if(empty($result)){
        return false;
    }

    if(false === $annotationName){
        return $result;
    }

    // 检测 是否 设置了该属性
    if(!array_key_exists($annotationName,$result)){
        return false;
    }

    if(count($result[$annotationName]) < 1){
        return false;
    }

    return $result[$annotationName][0];
}

/**
 * 按控制器名称，动作名称  解析注解  是否是开放的API
 * @param $version
 * @param $controllerName
 * @param $actionName
 * @param string $classNameProfix
 * @return array|bool
 */
function getControllerActionAnnotationsIsApi($version,$controllerName, $actionName,$classNameProfix = 'app\\api'){
    return getControllerActionAnnotations($version, $controllerName, $actionName,'isApi',$classNameProfix);
}

/**
 * 按控制器名称，动作名称  解析注解  是否 不检测 token
 * @param $version
 * @param $controllerName
 * @param $actionName
 * @param string $classNameProfix
 * @return array|bool
 */
function getControllerActionAnnotationsIsNoCheckToken($version,$controllerName, $actionName,$classNameProfix = 'app\\api'){
    return getControllerActionAnnotations($version, $controllerName, $actionName,'isNoCheckToken',$classNameProfix);
}

/**
 * 按控制器名称，动作名称  解析注解  方法参数说明，API文档用
 * @param $version
 * @param $controllerName
 * @param $actionName
 * @param string $classNameProfix
 * @return array|bool
 */
function getControllerActionAnnotationsMethodParam($version,$controllerName, $actionName,$classNameProfix = 'app\\api'){
    return getControllerActionAnnotations($version, $controllerName, $actionName,'methodParam',$classNameProfix);
}

// ----------------------------------------------------- API 帮助 方法 ----------------------------------------------------------------------------------------

/**
 * 列表（二维数组）显示过滤
 * @param  array $arr 二维数组
 * @param array $fields 保留的字段
 * @return array
 */
function listShowFilter(array $arr,$fields = array()){
    $fanhui = [];
    foreach ($arr as $item){
        $tmp = modelShowFilter($item,$fields);
        if(!empty($tmp)){
            $fanhui[] = $tmp;
        }
    }
    return $fanhui;
}

/**
 * model（一维数组）显示过滤
 * @param array $arr 一维数组
 * @param array $fields 保留的字段
 * @return array
 */
function modelShowFilter(array $arr,$fields = array()){
    $tmp = [];
    foreach ($fields as $field){
        if(array_key_exists($field,$arr)){
            $tmp[$field] = $arr[$field];
        }
    }
    return $tmp;
}

/**
 * 修改 env文件
 * @param array $data
 */
function modifyEnv(array $data){
    $envPath = BASE_PATH . '../.env';
    $envData = parse_ini_file($envPath,true);
    foreach ($data as $key => $item) {
        if(array_key_exists($key,$envData)){
            $envData[$key] = $item;
        }
    }
    $envText = [];
    foreach ($envData as $key => $item) {
        $envText[] = $key . ' = ' . $item;
    }
    file_put_contents($envPath, join("\n",$envText));
}

/**
 * 获取请求IP
 * @return string
 */
function ip() {
    //strcasecmp 比较两个字符，不区分大小写。返回0，>0，<0。
    if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
        $ip = getenv('HTTP_CLIENT_IP');
    } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
        $ip = getenv('HTTP_X_FORWARDED_FOR');
    } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
        $ip = getenv('REMOTE_ADDR');
    } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    $res =  preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
    return $res;
}

/**
 * 检测是否手机号码
 * @param $text
 */
function isMobilePhone($text){
    return preg_match("/^1[0-9]{1}\d{9}$/",$text);
}

/**
 * 是否 正整数
 * @param $text
 * @return false|int
 */
function isIntegerNumber($text){
    return preg_match("/^\d*$/",$text);
}

/**
 * 判断是否合法车牌号
 * @param $license
 * @return false|int
 */
function isCarLicense($license){
    $reg = "/^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[a-zA-Z](([DF]((?![IO])[a-zA-Z0-9](?![IO]))[0-9]{4})|([0-9]{5}[DF]))|[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1})$/u";

    return preg_match($reg, $license);
}

/**
 * 字符串截取
 * @param $text
 * @param $length
 * @param string $suffix
 * @return string
 */
function subtext($text, $length , $suffix = '...'){
    if(mb_strlen($text, 'utf8') > $length)
        return mb_substr($text, 0, $length, 'utf8') . $suffix;
    return $text;
}

/**
 * 获取图片地址，自动匹配cdn前缀
 * @param $cover_url
 * @return string
 */
function get_photo_url_cdn($photo_url){
    return $photo_url;
}

function read_all($dir)
{
    if (!is_dir($dir)) return false;
    $handle = opendir($dir);
    if ($handle) {
        while (($fl = readdir($handle)) !== false) {
            $temp = $dir . DIRECTORY_SEPARATOR . $fl;
            //如果不加  $fl!='.' && $fl != '..'  则会造成把$dir的父级目录也读取出来
            if (is_dir($temp) && $fl != '.' && $fl != '..') {
                read_all($temp);
            } else {
                if ($fl != '.' && $fl != '..') {
                    echo '文件：' . $temp . '<br>';
                }
            }
        }
    }
}

function read_dir($dir){
    $files=array();
    $dir_list=scandir($dir);
    foreach($dir_list as $file){
        if($file!='..' && $file!='.'){
            if(is_dir($dir.'/'.$file)){
                $files[]=read_dir($dir.'/'.$file);
            }else{
                $files[]=$file;
            }
        }
    }
    return $files;
}

/**
 * 安全显示model内的列，一般用于表单 添加 和编辑复用的表单
 * @param $model
 * @param $field
 * @param string $default
 * @return string
 */
function safeShowModelField($model,$field,$default = ''){
    if(empty($model)){
        return $default;
    }
    if(empty($field)){
        return $default;
    }
    // key 不存在，返回默认
    if(!array_key_exists($field,$model)){
        return $default;
    }

    return $model[$field];
}

/**
 * 从 goods 表的thumns 列中取出第一张图片地址
 * @param $thumbs
 * @return string
 */
function getGoodsThumb($thumbs){
    if(empty($thumbs)){
        return '';
    }
    $tmp = explode(',',$thumbs);
    if(empty($tmp)){
        return '';
    }
    return reset($tmp);
}

/**
 * 显示商品分类
 * @param $listShowCategory key 为id
 * @param $index
 * @return string
 */
function getGoodsCates($listShowCategory,$index){
    if(!array_key_exists($index,$listShowCategory)){
        return '分类不存在';
    }

    return $listShowCategory[$index];
}

/**
 * 数据按key 进行差集 合并 保留数组1的全部，数组2中存在，数组1不存的部分进行合并
 * @param $arr1
 * @param $arr2
 * @return array
 */
function array_diff_key_merge($arr1,$arr2){
    $chajis = array_diff_key($arr2,$arr1);
    return array_merge($arr1, $chajis);
}

/**
 * 分转元
 * @param $branch 分
 * @return string
 */
function getMoneyForBranch($branch){
    return fenToYuan($branch);
}
/**
 * 分转元
 * @param $branch 分
 * @return string
 */
function fenToYuan($cent){
    return sprintf('%.2f', ($cent / 100));
}

/**
 * 元转分
 * @param $yuan
 * @return int  分
 */
function yuanToFen($yuan){
    $fen = ($yuan * 100);

    if (!is_numeric($fen)) {
        exception('元转分 输入的 '.$yuan.' 元不正确 转换后 ' . $fen . ' 分');
    }

    return $fen;
}

/**
 * 微信头像转换成系统的头像
 * @param $headimgurl
 */
function headimgurl2avatar($headimgurl){
    $tmp = explode('/',$headimgurl);
    if(empty($tmp)){
        return '';
    }
    if(count($tmp) < 1){
        return '';
    }
    $tmp[count($tmp)-1] = '0';
    return join('/',$tmp);
}

/**
 * 获取 h5 端 member 表 openid
 * @param $mobile
 */
function getWapMemberOpenId($mobile){
    return 'wap_user_' . $mobile;
}

/**
 * 获取 h5 端 member 表 nickname
 * @param $mobile
 * @return string
 */
function getWapMemberNickname($mobile){
    if(!isMobilePhone($mobile)){
        return '手机号码格式错误';
    }
    return substr_replace($mobile, '****', 3, 4);
}

/**
 * 设置项目ID
 * @param $projectId
 */
function setProjectId($projectId){
    session('projectId',$projectId);
}

/**
 * 获取项目ID 如果不启用多项目，返回 0
 * @return mixed
 */
function getProjectId(){
    return session('projectId');
}

/**
 * 处理富文本内的图片，对其进行延迟加载
 * @param string $html
 * @return null|string|string[]
 */
function imgLazyJs($html = '')
{
    $html = preg_replace_callback('/<img.*?src=[\\\\\'| \\"](.*?(?:[\\.gif|\\.jpg|\\.png|\\.jpeg]?))[\\\\\'|\\"].*?[\\/]?>/', function($matches) {
        return preg_replace('/src=/', 'src="" data-lazy=', $matches[0]);
    }, $html);
    return $html;
}

/**
 * 创建订单号
 * @return string
 */
function build_order_no(){
    list($msec, $sec) = explode(' ', microtime());
    $haomiao = (sprintf('%04d',(floatval($msec) * 10000)));
    return date('ymdHis').$haomiao;
}

/**
 * 根据 订单model 来计算 应付  应付 =  total_price + dispatch_price
 * @param $orderModel
 * @return string
 */
function getOrderPayableByModel($orderModel){
    /*
    if(empty($orderModel['dispatch_price'])){
        $orderModel['dispatch_price'] = 0;
    }
    if(empty($orderModel['dispatch_price_change'])){
        $orderModel['dispatch_price_change'] = 0;
    }
    if(empty($orderModel['total_price_change'])){
        $orderModel['total_price_change'] = 0;
    }
    $yingfu = ($orderModel['total_price'] + $orderModel['dispatch_price'] + $orderModel['dispatch_price_change'] + $orderModel['total_price_change']);
    */
    return fenToYuan($orderModel['total_price'] + $orderModel['dispatch_price']);
}

/**
 * 应付运费
 * @param $orderModel
 * @return string
 */
function getOrderPayableDispatchPriceByModel($orderModel){
    return fenToYuan($orderModel['dispatch_price']);
}

/**
 * 订单是否改价
 * @param $orderModel
 * @return bool
 */
function orderIsChangePrice($orderModel){
    if($orderModel['total_price_change'] != 0){
        return true;
    }
    if($orderModel['dispatch_price_change'] != 0){
        return true;
    }
    return false;
}

/**
 * 根据 订单model 来 获取 价格明细 html
 * @param $orderModel
 * @return string table html
 */
function getOrderPriceDetailByModel($orderModel){
    $html[] = '<table style=\'width:100%;\'>';
    $html[] = '<tr><td style=\'border:none;text-align:right;\'>商品小计：</td><td class=\'total_price\' style=\'border:none;text-align:right;\'>￥'.fenToYuan($orderModel['original_total_price']).'</td></tr>';
    if ($orderModel['total_price_change'] != 0) {
        $html[] = '<tr><td style=\'border:none;text-align:right;\'>卖家改价：</td><td style=\'border:none;text-align:right;';
        if($orderModel['total_price_change'] > 0){
            $html[] = 'color:red;';
        }
        else{
            $html[] = 'color:green;';
        }
        $html[] = '\'>';
        if($orderModel['total_price_change'] > 0){
            $html[] = '+';
        }
        else{
            $html[] = '-';
        }
        $html[] = '￥'.fenToYuan(abs($orderModel['total_price_change'])).'</td></tr>';
    }

    $html[] = '<tr><td style=\'border:none;text-align:right;\'>运费：</td><td style=\'border:none;text-align:right;\'>￥'.$orderModel['original_dispatch_price'].'</td></tr>';

    if ($orderModel['dispatch_price_change'] != 0) {
        $html[] = '<tr><td style=\'border:none;text-align:right;\'>卖家改运费：</td><td style=\'border:none;text-align:right;';
        if($orderModel['dispatch_price_change'] > 0){
            $html[] = 'color:red;';
        }
        else{
            $html[] = 'color:green;';
        }
        $html[] = '\'>';
        if($orderModel['dispatch_price_change'] > 0){
            $html[] = '+';
        }
        else{
            $html[] = '-';
        }
        $html[] = '￥'.fenToYuan(abs($orderModel['dispatch_price_change'])).'</td></tr>';
    }
    $html[] = '<tr><td style=\'border:none;text-align:right;\'>应收款：</td><td class=\'payable\' style=\'border:none;text-align:right;\'>￥'.getOrderPayableByModel($orderModel).'</td></tr>';
    $html[] = '</table>';
    return join('',$html);
}

/**
 * 服务返回数据列表过滤
 * @param array $dataList 原始数据
 * @param array $showField 显示的列
 * @return array 过滤后的数据
 */
function serviceReturnDataListFieldFilter(array $dataList,array $showField){
    foreach ($dataList as $r => $row) {
        foreach ($row as $key => $item) {
            if (!in_array($key, $showField)) {
                unset($dataList[$r][$key]);
            }
        }
    }
    return $dataList;
}

/**
 * 清除空格
 * @param array $rows
 * @return array
 */
function arrayCleanUpSpace(array $rows){
    foreach ($rows as &$item){
        if(is_string($item)){
            $item = trim($item);
        }
    }
    unset($item);

    return $rows;
}

function assoc_unique($arr, $key) {
    $tmp_arr = array();
    foreach ($arr as $k => $v) {
        if (in_array($v[$key], $tmp_arr)) {//搜索$v[$key]是否在$tmp_arr数组中存在，若存在返回true
            unset($arr[$k]);
        } else {
            $tmp_arr[] = $v[$key];
        }
    }
    sort($arr); //sort函数对数组进行排序
    return $arr;
}

/**
 * 从 $goodsModel 中获取 $option
 * @param $goodsModel
 * @param $optionId
 * @return array
 */
function getGoodsOption($goodsModel,$optionId){
    foreach ($goodsModel['options'] as $option) {
        if ($option['id'] == $optionId) {
            return $option;
        }
    }

    return [];
}

/**
 * 从 $goodsModel 中获取 $option 中的某列
 * @param $goodsModel
 * @param $optionId
 * @param $field
 * @return string
 */
function getGoodsOptionField($goodsModel,$optionId,$field){
    foreach ($goodsModel['options'] as $option) {
        if ($option['id'] == $optionId) {
            return $option[$field];
        }
    }
    return '';
}

/**
 * 获取规格标题，如果是默认的话，不显示
 * @param $goodsModel
 * @param $optionId
 * @return string
 */
function getGoodsOptionTitle($goodsModel,$optionId){
    $optionModel = getGoodsOption($goodsModel,$optionId);
    if (empty($optionModel)) {
        return '';
    }
    if(config('site.goods_option_specs_val') == $optionModel['specs']){
        return '';
    }
    else{
        return $optionModel['title'];
    }
}

function ifDefaultOption($specs){
    return config('site.goods_option_specs_val') == $specs;
}

function setMyProject($projectList){
    session('myProject',$projectList);
}
function getMyProject(){
    return session('myProject');
}

/**
 * 获取排序后的分类
 * @param  array $data [description]
 * @param  integer $pid [description]
 * @param string $parentIdName
 * @param  string $pre [description]
 * @return array
 */
function getSortedCategory(&$data, $pid = 0 , $parentIdName = 'parent_id', $pre = ""){
    $temp = array();
    $curdata=array_filter($data,function($item) use ($pid,$parentIdName){
        return $item[$parentIdName] == $pid;
    });

    $count=count($curdata);

    $idx=0;
    foreach ($curdata as $v) {
        $idx++;
        $islast=$idx==$count?true:false;
        $v['html'] =$islast?($pre.'└─'):($pre.'├─');
        $temp[] = $v;
        if($islast){
            $temp = array_merge($temp, getSortedCategory($data, $v['id'],$parentIdName, $pre.'　　'));
        }else{
            $temp = array_merge($temp, getSortedCategory($data, $v['id'],$parentIdName, $pre.'│　'));
        }

    }
    return $temp;
}

/**
 * 获取商品状态查询条件
 * @param $show
 * @param bool $baohanDeleteTime
 * @return array
 */
function getGoodsWhere($show,$baohanDeleteTime = true){
    $where = [];
    switch ($show) {
        case 4:
            $where[] = ['g.delete_time','>',0];
            break;
        case 3:
            $where[] = ['g.status','=',0];
            if (true == $baohanDeleteTime) {
                $where[] = ['g.delete_time','<',1];
            }
            break;
        case 2:
            $where[] = ['g.status','>',0];
            $where[] = ['g.stock','<',1];
            if (true == $baohanDeleteTime) {
                $where[] = ['g.delete_time','<',1];
            }
            break;
        case 1:
            $where[] = ['g.status','>',0];
            $where[] = ['g.stock','>',0];
            if (true == $baohanDeleteTime) {
                $where[] = ['g.delete_time','<',1];
            }
            break;
    }

    return $where;
}

/**
 * 获取图片地址，自动匹配cdn前缀
 * @param $photoUrl
 * @return string
 */
function getPhotoCdnUrl($photoUrl){
    // 包含全地址路径，不进行转换
    if (strpos($photoUrl, 'http://') === 0) {
        return $photoUrl;
    }
    if (strpos($photoUrl, 'https://') === 0) {
        return $photoUrl;
    }
    return env('PHOTO_CDN_URL','').$photoUrl;
}

function getRateLimitAdapter(){
    $type = env('RATE_LIMIT_ADAPTER_TYPE');
    if (empty($type)) {
        exception('API限流器类型未配置');
    }
    $type = strtolower($type);
    if ('redis' == $type) {
        $redis = new \Redis();
        $redis->connect(env('RATE_LIMIT_ADAPTER_HOST'),env('RATE_LIMIT_ADAPTER_PORT'));
        // 指定数据库，不跟其他缓存冲突
        $redis->select(2);
        $adapter = new \PalePurple\RateLimit\Adapter\Redis($redis);
    } elseif ('memcached' == $type) {
        $memcached = new \Memcached();
        $memcached->addServer(env('RATE_LIMIT_ADAPTER_HOST'), env('RATE_LIMIT_ADAPTER_PORT'));
        $adapter = new \PalePurple\RateLimit\Adapter\Memcached($memcached);
    }
    else{
        exception('API限流器类型 不支持 ' . $type);
    }

    return $adapter;
}

/**
 * 过滤emoji表情
 * @param $str
 * @return string|string[]|null
 */
function filterEmoji($str) {
    $str = preg_replace_callback('/./u', function (array $match) {
        return strlen($match[0]) >= 4 ? '' : $match[0];
    }, $str);
    return $str;
}